
package Main;

import Engine.Game.GameDisplay;
import UserInterface.Navigator;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Image;
import javax.microedition.midlet.*;
import javax.microedition.rms.InvalidRecordIDException;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;
import javax.microedition.rms.RecordStoreNotOpenException;

/**
 * @author Gerardo Galíndez
 */

public class Tuxedo extends MIDlet {

    private Navigator navigator;
    private Display display;
    private Alert splashTec;
    private Image imgTec;
    private GameDisplay screen;
    private GameDisplay currentScreen;
    private FileConnection fileManager;
    private InputStream scanner;
    private String characterData;
    private byte[] loadData;
    private int current;
    private int bytesRead;
    private boolean isPaused;
    private byte[] data;
    private int newCharacter;
    /**
     * Tuxedo integer index code representing the Navigator screen.
     */
    public static final int NAVIGATOR = 0;
    /**
     * Tuxedo integer index code representing the Game screen.
     */
    public static final int GAME_SCREEN = 1;
     /**
     * Tuxedo integer index code representing Lyn's character code.
     */
    public static final int LYN = 2;
    /**
     * Tuxedo integer index code representing Eliwood's character code.
     */
    public static final int ELIWOOD = 3;
    /**
     * Tuxedo integer index code representing Eirik's character code.
     */
    public static final int EIRIK = 4;
    /**
     * Tuxedo integer index code representing file one character code.
     */
    public static final int FILE_ONE = 5;
    /**
     * Tuxedo integer index code representing file two character code.
     */
    public static final int FILE_TWO = 6;
    /**
     * Tuxedo integer index code representing file three character code.
     */
    public static final int FILE_THREE  = 7;
    /**
     * Tuxedo integer index code representing no file
     */
    public static final int NO_FILE = 8;
    /**
     * Tuxedo integer index code representing the first high score file
     */
    public static final int HIGH_SCORES_FILE_ONE = 9;
    /**
     * Tuxedo integer index code representing the second high score file
     */
    public static final int HIGH_SCORES_FILE_TWO = 10;
    /**
     * Tuxedo integer index code representing the third high score file
     */
    public static final int HIGH_SCORES_FILE_THREE = 11;
    private char difficulty;
    /**
     * Tuxedo character code representing the easy difficulty
     */
    public static final char EASY = 'a';
    /**
     * Tuxedo character code representing the medium difficulty
     */
    public static final char MEDIUM = 'b';
    /**
     * Tuxedo character code representing the hard difficulty
     */
    public static final char HARD = 'c';


    /**
     * Creates the application container, starting with the Navigator, which loads the main menu.
     */
    public Tuxedo() {
        current = NAVIGATOR;
        display = Display.getDisplay(this);
        try {
            imgTec = Image.createImage("/Images/UserInterface/ITESM.png");
            splashTec = new Alert(null,null,imgTec, AlertType.INFO);
        } catch ( IOException ex ) {
            ex.printStackTrace();
        }
        this.difficulty = Tuxedo.EASY;
        this.isPaused = false;
    }

    /**
     * Sets the Display to the current running screen.
     */
    public void startApp() {
        if ( !this.isPaused ) {
            display.setCurrent(splashTec);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            this.switchDisplay(current, true, Tuxedo.NO_FILE, true);
        } else {
            this.isPaused = false;
        }
        if(navigator != null) {
            navigator.resumeMusic();
        }
        if(currentScreen != null) {
            currentScreen.resumeMusic();
        }
    }

    /**
     * Sends a pause signal to the currently running screen.
     */
    public void pauseApp() {
        if(navigator != null) {
            navigator.toggleMusic();
        }
        System.out.println(currentScreen);
        if(currentScreen != null) {
            currentScreen.toggleMusic();
        }
        this.isPaused = true;
        
    }

    /**
     * Brings down the application. If unconditional is true, it sends a signal of finalization to the currently running screen. If not, it
     * checks the memory status and decideds if the application should be killed or not.
     * @param unconditional Decides whether if the finalization is an order or a suggestion.
     */
    public void destroyApp(boolean unconditional) {
        if (navigator != null) {
            navigator.finalize();
        }
        if(screen != null) {
            //gameScreen.finalize();
            screen = null;
        }
        System.out.println("App Destroyed");
    }

    /**
     * Destroys the currently loaded objects. If exitFlag is true, the method class destroyApp() and notifyDestroyed() for the OS to clean up
     * the consumed resources.
     * @param exitFlag
     */
    public void shutDownApp(boolean exitFlag) {
        navigator = null;
        screen = null;
        if (exitFlag) {
            this.destroyApp(true);
            this.notifyDestroyed();
        }
    }

    /**
     * Return the character code
     * @return the character code
     */
    public int getCharacterCode() {
        return newCharacter;
    }

    /**
     * Sets "newCharacter" with a Tuxedo integer index code to create a new game.
     * @param characterCode
     */
    public void setCharacterCode(int characterCode) {
        newCharacter = characterCode;
    }

    /**
     * Switches the Display to the corresponding screen that was chosen.
     * @param displayCode
     */
    public void switchDisplay(int displayCode, boolean isNewGame, int file, boolean defaultLanguage) {
        current = displayCode;
        switch(current) {
            case NAVIGATOR:
                if (navigator == null) {
                    navigator = new Navigator(this);
                    navigator.inicialize(display);
                } else {
                    navigator.inicialize(display);
                }
                break;
            case GAME_SCREEN:
                if ( file == Tuxedo.FILE_ONE || file == Tuxedo.FILE_TWO || file == Tuxedo.FILE_THREE ) {
                    this.loadData = this.readData(file);
                    this.characterData = new String(loadData, 0, this.bytesRead);
                }
                screen = new GameDisplay(this, newCharacter, isNewGame, this.characterData, defaultLanguage, this.difficulty);
                currentScreen = screen;
                display.setCurrent(screen);
                break;
            default:
                System.out.println("Fatal error");
                this.shutDownApp(true);
        }
    }

    /**
     * Sets the corresponding difficulty of the game
     * @param difficulty of the game
     */
    public void setDifficulty(char difficulty){
        this.difficulty = difficulty;
    }

/**
     * Write to a file the stats of the player and the current scene
     * @param data to be saved
     * @param fileNumber where data will be saved
     */
    public void writeData(byte[] data, int fileNumber){
        try {
            switch ( fileNumber ) {
                case FILE_ONE :
                    this.fileManager = (FileConnection) Connector.open("file:///e:/FileOne.txt", Connector.READ_WRITE);
                    break;
                case FILE_TWO :
                    this.fileManager = (FileConnection) Connector.open("file:///e:/FileTwo.txt", Connector.READ_WRITE);
                    break;
                case FILE_THREE :
                    this.fileManager = (FileConnection) Connector.open("file:///e:/FileThree.txt", Connector.READ_WRITE);
                    break;
                default :
                    System.out.println("Index out of bounds");
            }

            if ( !fileManager.exists() ) {
                fileManager.create();
            }

            OutputStream printer = fileManager.openOutputStream();

            printer.write(data);

            printer.close();
            fileManager.close();

        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * The file to be loades when need to load a game
     * @param fileNumber where data is located
     * @return the stats of the character and the current scene as a array of bytes
     */
    public byte[] readData(int fileNumber){
        try {
            switch ( fileNumber ) {
                case FILE_ONE :
                    this.fileManager = (FileConnection) Connector.open("file:///e:/FileOne.txt", Connector.READ_WRITE);
                    break;
                case FILE_TWO :
                    this.fileManager = (FileConnection) Connector.open("file:///e:/FileTwo.txt", Connector.READ_WRITE);
                    break;
                case FILE_THREE :
                    this.fileManager = (FileConnection) Connector.open("file:///e:/FileThree.txt", Connector.READ_WRITE);
                    break;
                default :
                    System.out.println("Index out of bounds");
            }

            if ( !fileManager.exists() ) {
                throw new IOException("The file doesn't exist");
            }

            this.scanner = fileManager.openInputStream();
            data = new byte[512];
            bytesRead = scanner.read(data);

            scanner.close();
            fileManager.close();

        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return data;
    }

}